package com.soft.baseexercise.exercise;

import java.util.Scanner;

/**
 * @author yzh
 * @desc TODO
 * @date 2025/4/15
 */

public class PerpetualCalendar {

    // 星期数组
    static String[] week = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};

    // 每个月的天数（非闰年）
    static int[] day = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (true){
            System.out.println("*--------------------欢迎使用万年历--------------------*");
            System.out.println("请输入年份（1900以后）：");
            int year = sc.nextInt();

            if (year < 1900) {
                System.out.println("年份输入无效，请输入1900后的年份。");
                continue;
            }

            System.out.println("请输入月份（1-12）：");
            int month = sc.nextInt();

            if (month < 1 || month > 12) {
                System.out.println("月份输入无效，请输入1-12之间的数字。");
                continue;
            }

            System.out.println("-----------------------------------------------------");
            printCalendar(year, month);
            System.out.println("------------------继续Y|y    退出N|n------------------");

            String str = sc.next();
            if (str.equalsIgnoreCase("N")) {
                System.out.println("-------------------感谢使用万年历！!-------------------");
                break;
            } else if (!str.equalsIgnoreCase("Y")) {
                System.out.println("输入无效，程序将退出。");
                break;
            }
        }
    }

    // 打印日历（从星期日开始）
    public static void printCalendar(int year, int month) {

        // 获取某月的天数
        int dayOfMonth = getDayOfMonth(year, month);

        // 打印星期标题（从星期日开始）
        for (String weekName : week) {
            System.out.print(weekName + "\t");
        }
        System.out.println();

        // 计算该月第一天是星期几（蔡勒公式结果：0=星期六，1=星期日，...，6=星期五）
        int firstDayOfWeek = formula(year, month, 1);

        // 转换为从星期日开始的索引
        firstDayOfWeek = (firstDayOfWeek + 6) % 7;

        int day = 1;
        // 打印初始空格（对齐第一天）
        for (int i = 0; i < firstDayOfWeek; i++) {
            System.out.print("\t\t");
        }

        // 打印日期
        while (day <= dayOfMonth) {
            for (int i = firstDayOfWeek; i < 7 && day <= dayOfMonth; i++) {
                System.out.print(day + "\t\t");
                day++;
            }
            System.out.println();
            firstDayOfWeek = 0; // 第一行之后从星期日开始
        }
    }

    //蔡勒公式计算日数是星期几
    public static int formula(int year, int month, int day) {
        // 如果是1月或2月，当作前一年的13月或14月
        if (month == 1 || month == 2) {
            month += 12;
            year--;
        }

        int century = year / 100; // 世纪数
        int yearOfCentury = year % 100; // 年份后两位

        /*蔡勒公式计算日数是星期几
        h = (q + ⌊(13(m+1)/5⌋ + K + ⌊K/4⌋ + ⌊J/4⌋ + 5J) mod 7
        h 是星期几（0=星期六, 1=星期日, 2=星期一,...,6=星期五）
        q 是日期中的日数（1-31）
        m 是月份（3=三月,4=四月,...,14=二月）
        K 是年份的后两位数
        J 是年份的前两位数*/

        int h = (day + (13 * (month + 1)) / 5 + yearOfCentury +
                yearOfCentury / 4 + century / 4 + 5 * century) % 7;

        return h < 0 ? h + 7 : h;
    }

    // 获取某月的天数
    public static int getDayOfMonth(int year, int month) {
        return month == 2 && isLeapYear(year) ? 29 : day[month - 1];
    }

    // 判断闰年
    public static boolean isLeapYear(int year) {
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }
}